package com.tuomaxu.core;

import com.tuomaxu.config.Configuration;
import com.tuomaxu.config.MappedStatement;

import java.lang.reflect.*;
import java.util.List;

public class SqlSessionImp implements SqlSession {
    private Configuration configuration;
    public SqlSessionImp(Configuration configuration) {
        this.configuration = configuration;
    }

    @Override
    public <E> List<E> selectList(String statementid, Object... params) throws Exception {
        Executor executor = new ExecutorImp();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementid);
        List<E> list = executor.query(configuration, mappedStatement, params);
        return list;
    }

    @Override
    public <T> T selectOne(String statementid, Object... params) throws Exception {
        List<T> objects = selectList(statementid, params);
        if (objects.size() != 1){
            throw new Exception("数据有误");
        }
        return objects.get(0);
    }

    @Override
    public void insert(String statementid, Object... params) throws Exception {
        Executor executor = new ExecutorImp();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementid);
        if(!"insert".equals(mappedStatement.getSqlType())){
            throw  new Exception("操作错误");
        }
        executor.execute(configuration,mappedStatement,params);

    }

    @Override
    public void update(String statementid, Object... params) throws Exception {
        Executor executor = new ExecutorImp();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementid);
        if(!"update".equals(mappedStatement.getSqlType())){
            throw  new Exception("操作错误");
        }
        executor.execute(configuration,mappedStatement,params);
    }

    @Override
    public void delete(String statementid, Object... params) throws Exception {
        Executor executor = new ExecutorImp();
        MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementid);
        if(!"delete".equals(mappedStatement.getSqlType())){
            throw  new Exception("操作错误");
        }
        executor.execute(configuration,mappedStatement,params);
    }

    //怎么声明一个有时候是有返回值，有时候是void的方法呢？
    @Override
    public <T> T  getMapper(Class<?> mapperClass) {
        //TODO
        ClassLoader classLoader = SqlSessionImp.class.getClassLoader();
        Class[] arr = {mapperClass};
        Object proxyInstance = Proxy.newProxyInstance(classLoader, arr, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //准备参数 1：statmentid :sql语句的唯一标识：namespace.id= 接口全限定名.方法名
                String methodName = method.getName();
                String className = method.getDeclaringClass().getName();
                //通过id获取mappedStatement，获取sqlType，通过sqlType选择执行响应的方法
                String statementId = className+"."+methodName;
                MappedStatement mappedStatement = configuration.getMappedStatementMap().get(statementId);
                String sqlType = mappedStatement.getSqlType();
                if("select".equals(sqlType)){
                    Type genericReturnType = method.getGenericReturnType();
                    // 判断是否进行了 泛型类型参数化
                    if(genericReturnType instanceof ParameterizedType){
                        List<Object> objects = selectList(statementId, args);
                        return objects;
                    }
                    return selectOne(statementId,args);
                }
                if("insert".equals(sqlType)){
                    insert(statementId,args);
                    return null;
                }
                if("update".equals(sqlType)){
                    update(statementId,args);
                    return null;
                }
                if("delete".equals(sqlType)){
                    delete(statementId,args);
                    return null;
                }
                throw new Exception("sql类型错误");
            }
        });
        return (T) proxyInstance;
    }
}
